package net.xo68.destiny.starter.worker.sched;

import lombok.extern.slf4j.Slf4j;
import net.xo68.destiny.contract.domain.job.TriggerParameter;
import net.xo68.destiny.contract.domain.report.DatagramSerializer;
import net.xo68.destiny.contract.domain.report.JobHandleReplyDatagram;
import net.xo68.destiny.contract.enums.handler.JobHandlePhaseEnum;
import net.xo68.destiny.contract.enums.handler.JobHandleStateEnum;
import net.xo68.destiny.core.timingwheel.process.EventProcessorContext;
import net.xo68.destiny.core.util.TimeUtils;
import net.xo68.destiny.starter.common.sched.TaskTimeoutEventHandler;
import net.xo68.destiny.starter.worker.handler.JobHandleReplyProvider;
import net.xo68.destiny.starter.worker.handler.JobHandler;
import net.xo68.destiny.starter.worker.handler.JobHandlerFactory;
import net.xo68.destiny.starter.worker.logger.JobLoggerFactory;
import org.springframework.stereotype.Component;

import java.time.Duration;

/**
 * 超时项任务超时事件处理实现
 * @author wuxie
 * @version 2020-10-26
 */
@Slf4j
@Component
public class TimeoutEventHandlerImpl implements TaskTimeoutEventHandler {

    private final JobLoggerFactory jobLoggerFactory;

    private final JobHandlerFactory jobHandlerFactory;

    protected final JobHandleReplyProvider jobHandleReplyProvider;

    protected final DatagramSerializer datagramSerializer;


    public TimeoutEventHandlerImpl(JobLoggerFactory jobLoggerFactory, JobHandlerFactory jobHandlerFactory, JobHandleReplyProvider jobHandleReplyProvider,DatagramSerializer datagramSerializer) {
        this.jobLoggerFactory=jobLoggerFactory;
        this.jobHandlerFactory = jobHandlerFactory;
        this.jobHandleReplyProvider = jobHandleReplyProvider;
        this.datagramSerializer=datagramSerializer;
    }

    @Override
    public void onBefore(EventProcessorContext<TriggerParameter> processorContext) {
        processorContext.setReply(true);
        //处理开始上报
        JobHandleReplyDatagram replyDatagram=JobHandleReplyDatagram.builder(datagramSerializer).instanceId(processorContext.triggerParameter().getInstanceId())
                .phase(JobHandlePhaseEnum.START)
                .state(JobHandleStateEnum.SUCCESS)
                .start(TimeUtils.ofDate(processorContext.getStartTime()))
                .build();
        this.jobHandleReplyProvider.push(replyDatagram);
    }

    @Override
    public void onEvent(EventProcessorContext<TriggerParameter> processorContext) throws Exception {
        JobHandler jobHandler=this.jobHandlerFactory.getJobHandler(processorContext.triggerParameter().getJobHandler());
        jobHandler.setJobLogger(this.jobLoggerFactory.getLogger(processorContext.triggerParameter().getInstanceId()));
        //jobHandler.setJobHandleReplyProvider(this.jobHandleReplyProvider);
        try {
            jobHandler.execute(processorContext);
        }catch (Exception e){
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public void onComplete(EventProcessorContext<TriggerParameter> processorContext) {
        Duration duration=TimeUtils.calculateTimeSpan(processorContext.getStartTime(),processorContext.getFinishTime());
        log.debug("use time:{}ms",duration.toMillis());
        if(processorContext.getResult()!=null && processorContext.getResult() instanceof JobHandleReplyDatagram){
            JobHandleReplyDatagram replyDatagram=processorContext.getResult();
            replyDatagram.setStart(TimeUtils.ofDate(processorContext.getStartTime()));
            replyDatagram.setEnd(TimeUtils.ofDate(processorContext.getFinishTime()));
            //log.info("{}", replyDatagram);
            if(processorContext.isReply()){
                //处理结束上报
                this.jobHandleReplyProvider.push(replyDatagram);
            }
        }
    }
}
